#ifndef DATABASE_H_
#define DATABASE_H_

#include <map>
#include <list>
#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <typeinfo>
#include "../interface/IdAble.h"
#include "../interface/ToStringAble.h"
#include "../basic/MyException.h"
#include "../ads/IntToString.h"
#include "../ads/typesDefinition.h"

namespace common {

/**
 * Szablon Klasy DataBase służy do przechowywania elementów
 * typu (Constraint,Parameter,Primitive,Point).
 * Elemnt taki musi dziedziczyc po IdAble
 */

template<class Type1>
class DataBase: public ToStringAble {

public:
	typedef typename std::map<int, Type1> mapType;
	typedef typename std::map<int, Type1>::iterator mapTypeIter;

protected:
	std::string name;
	mapType* data;

public:


	DataBase(const std::string& name);

	/** do sekcji protected */
	Type1 add(Type1 item) throw (MyException);
	virtual void remove(int id) throw (MyException);
	Type1 get(int id) throw (MyException);
	bool isId(int id);
	int getMaxId(void);
	_keyType* getIds(void);
	/**end: do sekcji protected */
	std::string toString(void);

	int size();

	virtual ~DataBase();
};

template<class Type1>
DataBase<Type1>::DataBase(const std::string& name) :
	name(name) {
	data = new mapType();
}

template<class Type1>
bool DataBase<Type1>::isId(int id) {
	return (data->count(id));
}

template<class Type1>
_keyType* DataBase<Type1>::getIds(void) {
	_keyType* keys = new _keyType();
	mapTypeIter itr;
	for (itr = data->begin(); itr != data->end(); itr++) {
		int s= itr->first;
		keys->push_back(s);
	}
	return keys;
}

template<class Type1>
Type1 DataBase<Type1>::add(Type1 item) throw (MyException) {
	if (!isId(((IdAble*) item)->getId())) {
		data->insert(make_pair(item->getId(), item));
		return item;
	}
	throw MyException("E-RROR: Add - " + this->name
			+ " - element istniej juz w bazie , id=" + _intToStr(item->getId()));
}
template<class Type1>
void DataBase<Type1>::remove(int id) throw (MyException) {
	if (isId(id)) {
		delete get(id);
		data->erase(data->find(id));
		return;
	}
	throw MyException("E-RROR: Remove - BRAK w " + this->name
			+ " elementu o id = " + _intToStr(id));
}

template<class Type1>
Type1 DataBase<Type1>::get(int id) throw (MyException) {
	if (isId(id)) {
		return (data->find(id)->second);
	}
	throw MyException("E-RROR:Get - BRAK w " + this->name + " elementu o id = "
			+ _intToStr(id));
}
template<class Type1>
int DataBase<Type1>::getMaxId(void) {

	int out = 0;
	_keyType* keys = getIds();
	if (keys->size() != 0) {
		out = *(std::max_element(keys->begin(), keys->end()));
	}
	delete keys;
	return out;
}
template<class Type1>
std::string DataBase<Type1>::toString(void){

	std::stringstream out;

	for(mapTypeIter it = data->begin();it!=data->end();it++){
		out << it->second->toString() << std::endl;
	}
	return out.str();
}
template<class Type1>
int DataBase<Type1>::size(){
	return data->size();
}
template<class Type1>
DataBase<Type1>::~DataBase() {
	for (mapTypeIter its = data->begin(); its != data->end(); its++) {
		delete  its->second;
	}
	data->clear();
	delete data;
}


}

#endif /* DATABASE_H_ */
